/**
 * Copyright (c) 2019 Coder League
 * All rights reserved.
 *
 * File：IntegralRecordsService.java
 * History:
 *         2019年5月30日: Initially created, CJH.
 */
package club.coderleague.ilsp.service.integralrecords;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import javax.validation.ValidationException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import club.coderleague.ilsp.common.domain.enums.EntityState;
import club.coderleague.ilsp.common.domain.enums.IntegralChangedReason;
import club.coderleague.ilsp.common.domain.enums.IntegralRecordType;
import club.coderleague.ilsp.common.exception.MessageInfoException;
import club.coderleague.ilsp.common.exception.MessageWarnException;
import club.coderleague.ilsp.dao.IntegralRecordRefsDao;
import club.coderleague.ilsp.dao.IntegralRecordsDao;
import club.coderleague.ilsp.dao.MembersDao;
import club.coderleague.ilsp.dao.OrdersDao;
import club.coderleague.ilsp.entities.Integralrecordrefs;
import club.coderleague.ilsp.entities.Integralrecords;
import club.coderleague.ilsp.entities.Members;
import club.coderleague.ilsp.entities.Orders;

/**
 * 积分记录Service
 * 
 * @author CJH
 */
@Service
public class IntegralRecordsService {
	
	private @Autowired MembersDao membersDao;
	
	private @Autowired IntegralRecordsDao integralRecordsDao;
	
	private @Autowired IntegralRecordRefsDao integralRecordRefsDao;
	
	private @Autowired OrdersDao ordersDao;

	/**
	 * 清理过期积分
	 * 
	 * @author CJH 2019年5月30日
	 */
	public void updateCleanExpireIntegral() {
		List<Members> members = membersDao.findExistsExpireIntegral();
		if (members == null || members.isEmpty()) {
			return;
		}
		for (Members member : members) {
			// 清理会员过期积分
			List<Integralrecords> integralrecords = integralRecordsDao.findExpireByMemberid(member.getEntityid());
			// 需要清理积分数
			Integer expirenum = 0;
			for (Integralrecords integralrecord : integralrecords) {
				expirenum += (integralrecord.getRemainedintegral() - integralrecord.getLockedintegral());
				integralrecord.setRemainedintegral(integralrecord.getLockedintegral());
			}
			Integralrecords integralrecord = new Integralrecords(EntityState.VALID.getValue(), member.getEntityid(), IntegralRecordType.PAY.getValue(), 
					IntegralChangedReason.EXPIRE.getValue(), null, "过期自动清除", expirenum, null, null, new Date());
			integralRecordsDao.save(integralrecord);
		}
	}

	/**
	 * 锁定积分
	 * 
	 * @author CJH 2019年6月3日
	 * @param memberid 会员标识
	 * @param locknum 锁定积分
	 */
	public void updateLockIntegralByMemberid(Long memberid, Integer locknum) {
		// 校验参数有效性
		if (memberid == null) {
			throw new ValidationException("会员标识不能为空");
		}
		if ((locknum = locknum != null ? locknum : 0) <= 0) {
			throw new ValidationException("锁定积分不能小于等于0");
		}
		
		// 查询有效积分并校验有效性
		List<Integralrecords> integralrecords = integralRecordsDao.findValidByMemberid(memberid);
		if (integralrecords == null || integralrecords.isEmpty()) {
			throw new MessageInfoException("积分余额不足");
		}
		Integer lacknum = locknum;
		for (Integralrecords integralrecord : integralrecords) {
			if ((lacknum -= (integralrecord.getRemainedintegral() - integralrecord.getLockedintegral())) <= 0) {
				break;
			}
		}
		if (lacknum > 0) {
			throw new MessageInfoException("积分余额不足");
		}
		
		// 锁定积分
		for (Integralrecords integralrecord : integralrecords) {
			Integer usablenum = integralrecord.getRemainedintegral() - integralrecord.getLockedintegral();
			Integer thislocknum = locknum > usablenum ? usablenum : locknum;
			integralrecord.setLockedintegral(integralrecord.getLockedintegral() + thislocknum);
			if ((locknum -= thislocknum) == 0) {
				break;
			}
		}
	}
	
	/**
	 * 解锁锁定积分
	 * 
	 * @author CJH 2019年6月3日
	 * @param memberid 会员标识
	 * @param unlocknum 解锁积分
	 */
	public void updateUnlockIntegralByMemberid(Long memberid, Integer unlocknum) {
		if (memberid == null) {
			throw new ValidationException("会员标识不能为空");
		}
		if ((unlocknum = unlocknum != null ? unlocknum : 0) <= 0) {
			throw new ValidationException("解锁积分不能小于等于0");
		}
		
		// 查询已锁定积分并校验有效性
		List<Integralrecords> integralrecords = integralRecordsDao.findLockedByMemberid(memberid);
		if (integralrecords == null || integralrecords.isEmpty()) {
			throw new MessageInfoException("锁定积分余额不足");
		}
		Integer lacknum = unlocknum;
		for (Integralrecords integralrecord : integralrecords) {
			if ((lacknum -= integralrecord.getLockedintegral()) <= 0) {
				break;
			}
		}
		if (lacknum > 0) {
			throw new MessageInfoException("锁定积分余额不足");
		}
		
		// 解锁锁定积分
		Integer expirenum = 0;
		for (int i = integralrecords.size() - 1; i >= 0; i--) {
			Integralrecords integralrecord = integralrecords.get(i);
			Integer thisunlocknum = unlocknum > integralrecord.getLockedintegral() ? integralrecord.getLockedintegral() : unlocknum;
			integralrecord.setLockedintegral(integralrecord.getLockedintegral() - thisunlocknum);
			
			// 校验积分有效性
			if (integralRecordsDao.isExpireByEntityid(integralrecord.getEntityid())) {
				expirenum += (integralrecord.getRemainedintegral() - integralrecord.getLockedintegral());
				integralrecord.setRemainedintegral(integralrecord.getLockedintegral());
			}
			
			if ((unlocknum -= thisunlocknum) == 0) {
				break;
			}
		}
		if (expirenum > 0) {
			Integralrecords integralrecord = new Integralrecords(EntityState.VALID.getValue(), memberid, IntegralRecordType.PAY.getValue(), 
					IntegralChangedReason.EXPIRE.getValue(), null, "解除锁定过期清除", expirenum, null, null, new Date());
			integralRecordsDao.save(integralrecord);
		}
	}
	
	/**
	 * 使用积分
	 * 
	 * @author CJH 2019年6月3日
	 * @param orderid 订单标识
	 * @param useintegralnum 使用积分
	 */
	public void updateUseIntegralByOrderid(Long orderid, Integer useintegralnum) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		if ((useintegralnum = useintegralnum != null ? useintegralnum : 0) <= 0) {
			throw new ValidationException("使用积分不能小于等于0");
		}
		
		// 查询锁定积分并验证有效性
		Orders order = ordersDao.getOne(orderid);
		List<Integralrecords> integralrecords = integralRecordsDao.findLockedByMemberid(order.getMemberid());
		if (integralrecords == null || integralrecords.isEmpty()) {
			throw new MessageInfoException("锁定积分余额不足");
		}
		Integer lackintegralnum = useintegralnum;
		for (Integralrecords integralrecord : integralrecords) {
			if ((lackintegralnum -= integralrecord.getLockedintegral()) <= 0) {
				break;
			}
		}
		if (lackintegralnum > 0) {
			throw new MessageInfoException("锁定积分余额不足");
		}
		
		// 保存使用积分记录
		Integralrecords newintegralrecord = new Integralrecords(EntityState.VALID.getValue(), order.getMemberid(), IntegralRecordType.PAY.getValue(), 
				IntegralChangedReason.PAY.getValue(), orderid, new StringBuilder("订单抵扣(订单号：").append(orderid).append(")").toString(), 
				useintegralnum, null, null, new Date());
		integralRecordsDao.save(newintegralrecord);
		
		// 使用积分
		for (Integralrecords integralrecord : integralrecords) {
			Integer thisuseintegralnum = useintegralnum > integralrecord.getLockedintegral() ? integralrecord.getLockedintegral() : useintegralnum;
			integralrecord.setRemainedintegral(integralrecord.getRemainedintegral() - thisuseintegralnum);
			integralrecord.setLockedintegral(integralrecord.getLockedintegral() - thisuseintegralnum);
			integralRecordRefsDao.save(new Integralrecordrefs(EntityState.VALID.getValue(), newintegralrecord.getEntityid(), 
					integralrecord.getEntityid(), thisuseintegralnum, 0));
			if ((useintegralnum -= thisuseintegralnum) == 0) {
				break;
			}
		}
	}
	
	/**
	 * 退款积分
	 * 
	 * @author CJH 2019年8月25日
	 * @param orderid 订单标识
	 * @param refundnum 退款积分
	 */
	public void updateRefundIntegralByOrderid(Long orderid, Integer refundnum) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		if ((refundnum = refundnum!= null ? refundnum : 0) <= 0) {
			throw new ValidationException("退款积分不能小于等于0");
		}
		
		// 查询积分使用记录
		Integralrecords paymentintegralrecord = integralRecordsDao.findByOrderidAndRecordtype(orderid, IntegralRecordType.PAY.getValue());
		if (paymentintegralrecord == null) {
			throw new MessageWarnException("未找到积分支付记录");
		}
		List<Integralrecordrefs> integralrecordrefs = integralRecordRefsDao.findByPaymentrecordid(paymentintegralrecord.getEntityid());
		if (integralrecordrefs == null || integralrecordrefs.isEmpty()) {
			throw new MessageWarnException("未找到积分支付记录关系");
		}
		
		// 退款积分
		Integer expirenum = 0;
		for (int i = integralrecordrefs.size() - 1; i >= 0; i--) {
			Integralrecordrefs integralrecordref = integralrecordrefs.get(i);
			Integer thisrefundnum = refundnum > integralrecordref.getPaymentamount() ? integralrecordref.getPaymentamount() : refundnum;
			integralrecordref.setRefundamount(thisrefundnum);
			
			Integralrecords incomeintegralrecord = integralRecordsDao.getOne(integralrecordref.getIncomerecordid());
			incomeintegralrecord.setRemainedintegral(incomeintegralrecord.getRemainedintegral() + thisrefundnum);
			
			// 校验积分有效性
			if (integralRecordsDao.isExpireByEntityid(incomeintegralrecord.getEntityid())) {
				expirenum += (incomeintegralrecord.getRemainedintegral() - incomeintegralrecord.getLockedintegral());
				incomeintegralrecord.setRemainedintegral(incomeintegralrecord.getLockedintegral());
			}
			
			if ((refundnum -= thisrefundnum) == 0) {
				break;
			}
		}
		if (expirenum > 0) {
			Integralrecords integralrecord = new Integralrecords(EntityState.VALID.getValue(), paymentintegralrecord.getMemberid(), IntegralRecordType.PAY.getValue(), 
					IntegralChangedReason.EXPIRE.getValue(), null, "退款过期清除", expirenum, null, null, new Date());
			integralRecordsDao.save(integralrecord);
		}
	}
	
	/**
	 * 订单收入积分
	 * 
	 * @author CJH 2019年6月17日
	 * @param orderid 订单标识
	 */
	public void updateOrderIncomeIntegralByOrderid(Long orderid) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		
		// 保存订单收入积分记录
		Orders orders = ordersDao.getOne(orderid);
		BigDecimal paymenttotalbd = new BigDecimal(orders.getPaymenttotal());
		Integer integralnum = paymenttotalbd.setScale(0, BigDecimal.ROUND_DOWN).intValue();
		Integralrecords integralrecords = new Integralrecords(EntityState.VALID.getValue(), orders.getMemberid(), IntegralRecordType.INCOME.getValue(), 
				IntegralChangedReason.ORDER_REVENUE.getValue(), orderid, new StringBuilder("订单收入(订单号：").append(orders.getEntityid()).append(")").toString(), 
				integralnum, integralnum, 0, new Date());
		integralRecordsDao.save(integralrecords);
	}

	/**
	 * 收入积分
	 * 
	 * @author CJH 2019年8月8日
	 * @param memberid 会员标识
	 * @param incomenum 收入积分
	 * @param changedreason 变化原因
	 * @param reasondesc 原因描述
	 */
	public void updateIncomeIntegralByMemberid(Long memberid, Integer incomenum, IntegralChangedReason changedreason, String reasondesc) {
		// 校验参数有效性
		if (memberid == null) {
			throw new ValidationException("会员标识不能为空");
		}
		if ((incomenum = incomenum != null ? incomenum : 0) <= 0) {
			throw new ValidationException("收入积分不能小于等于0");
		}
		if (changedreason == null || !IntegralRecordType.INCOME.equals(changedreason.getType())) {
			throw new ValidationException("变化原因无效");
		}
		
		Integralrecords integralrecords = new Integralrecords(EntityState.VALID.getValue(), null, IntegralRecordType.INCOME.getValue(), 
				changedreason.getValue(), null, reasondesc, incomenum, incomenum, 0, new Date());
		integralRecordsDao.save(integralrecords);
	}
}
